package trim.common.inputdata;

import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.*;
import javax.xml.transform.dom.*;
import java.io.*;
import java.util.*;

import trim.common.*;

/**
 *
 * @author Sasha
 */
public class InputData
{
    private List<MaterialStock> materialStockList = new ArrayList();
    private List<FormatOrder> formatOrderList = new ArrayList();

    /**
     * Конструктор
     */
    public InputData()
    {
        super();
    }

    /**
     * Конструктор
     */
    public InputData(String fileName) throws InputDataException
    {
        super();
        loadDataFromXML(fileName);
    }

    /**
     * Конструктор
     */
    public InputData(InputStream inputStream) throws InputDataException
    {
        super();
        loadDataFromXML(inputStream);
    }

    /**
     * Конструктор
     */
    public InputData(File file) throws InputDataException
    {
        super();
        loadDataFromXML(file);
    }

    /**
     * Возвращает список Материал - количество
     */
    public List<MaterialStock> getMaterialStockList()
    {
        return materialStockList;
    }

    /**
     * Возвращает список Формат - количество
     */
    public List<FormatOrder> getFormatOrderList()
    {
        return formatOrderList;
    }

    /**
     * Метод сохраняет поля в XML файл
     */
    private void saveDataToXML(Writer writer) throws InputDataException
    {
        try
        {
            Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument();
            Element inputData = document.createElement("input-data");
            document.appendChild(inputData);
            Element materials = document.createElement("materials");
            inputData.appendChild(materials);
            Element formats = document.createElement("formats");
            inputData.appendChild(formats);
            for (MaterialStock materialCount : materialStockList)
            {
                Element material = document.createElement("material");
                Element element;
                element = document.createElement("length");
                element.appendChild(document.createTextNode(Integer.toString(materialCount.getMaterial().getLength())));
                material.appendChild(element);
                element = document.createElement("count");
                element.appendChild(document.createTextNode(Integer.toString(materialCount.getCount())));
                material.appendChild(element);
                element = document.createElement("knife-count");
                element.appendChild(document.createTextNode(Integer.toString(materialCount.getMaterial().getKnifeCount())));
                material.appendChild(element);
                element = document.createElement("knife-interval");
                element.appendChild(document.createTextNode(Integer.toString(materialCount.getMaterial().getKnifeInterval())));
                material.appendChild(element);
                element = document.createElement("min-edge");
                element.appendChild(document.createTextNode(Integer.toString(materialCount.getMaterial().getMinEdge())));
                material.appendChild(element);
                element = document.createElement("max-edge");
                element.appendChild(document.createTextNode(Integer.toString(materialCount.getMaterial().getMaxEdge())));
                material.appendChild(element);
                materials.appendChild(material);
            }
            for (FormatOrder formatCount : formatOrderList)
            {
                Element format = document.createElement("format");
                Element element;
                element = document.createElement("length");
                element.appendChild(document.createTextNode(Integer.toString(formatCount.getFormat().getLength())));
                format.appendChild(element);
                element = document.createElement("count");
                element.appendChild(document.createTextNode(Integer.toString(formatCount.getCount())));
                format.appendChild(element);
                formats.appendChild(format);
            }
            Source source = new DOMSource(document);
            StreamResult streamResult = new StreamResult(writer);
            Transformer transformer = TransformerFactory.newInstance().newTransformer();
            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.transform(source, streamResult);
            writer.flush();
            writer.close();
        }
        catch (Exception exception)
        {
            throw new InputDataException(exception);
        }
    }

    /**
     * Метод сохраняет поля в XML файл
     */
    public void saveDataToXML(String fileName) throws InputDataException
    {
        try
        {
            saveDataToXML(new OutputStreamWriter(new FileOutputStream(fileName), "UTF-8"));
        }
        catch (Exception exception)
        {
            throw new InputDataException(exception);
        }
    }

    /**
     * Метод сохраняет поля в XML файл
     */
    public void saveDataToXML(OutputStream outputStream) throws InputDataException
    {
        try
        {
            saveDataToXML(new OutputStreamWriter(outputStream, "UTF-8"));
        }
        catch (Exception exception)
        {
            throw new InputDataException(exception);
        }
    }

    /**
     * Метод сохраняет поля в XML файл
     */
    public void saveDataToXML(File file) throws InputDataException
    {
        try
        {
            saveDataToXML(new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
        }
        catch (Exception exception)
        {
            throw new InputDataException(exception);
        }
    }

    /**
     * Метод читает данные из XML и записывает их в поля
     */
    private void loadDataFromXML(Document document) throws InputDataException
    {
        try
        {
            NodeList materials = document.getElementsByTagName("material");
            NodeList formats = document.getElementsByTagName("format");
            materialStockList = new ArrayList(materials.getLength());
            formatOrderList = new ArrayList(formats.getLength());
            int mLength=materials.getLength();
            for (int i = 0; i < mLength; i++)
            {
                MaterialStock currentMaterial = new MaterialStock();
                Material material = new Material(
                     Integer.parseInt(((Element)materials.item(i)).getElementsByTagName("length").item(0).getTextContent()),
                     Integer.parseInt(((Element)materials.item(i)).getElementsByTagName("knife-count").item(0).getTextContent()),
                     Integer.parseInt(((Element)materials.item(i)).getElementsByTagName("knife-interval").item(0).getTextContent()),
                     Integer.parseInt(((Element)materials.item(i)).getElementsByTagName("min-edge").item(0).getTextContent()),
                     Integer.parseInt(((Element)materials.item(i)).getElementsByTagName("max-edge").item(0).getTextContent()));
                currentMaterial.setMaterial(material);
                currentMaterial.setCount(Integer.parseInt(((Element)materials.item(i)).getElementsByTagName("count").item(0).getTextContent()));
                materialStockList.add(currentMaterial);
            }
            int fLength=formats.getLength();
            for (int i = 0; i < fLength; i++)
            {
                FormatOrder currentFormat = new FormatOrder();
                currentFormat.setFormat(new Format(Integer.parseInt(((Element)formats.item(i)).getElementsByTagName("length").item(0).getTextContent())));
                currentFormat.setCount(Integer.parseInt(((Element)formats.item(i)).getElementsByTagName("count").item(0).getTextContent()));
                formatOrderList.add(currentFormat);
            }
        }
        catch (Exception exception)
        {
            throw new InputDataException(exception);
        }
    }

    /**
     * Метод читает данные из XML и записывает их в поля
     */
    public void loadDataFromXML(String fileName) throws InputDataException
    {
        try
        {
            loadDataFromXML(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(fileName));
        }
        catch (Exception exception)
        {
            throw new InputDataException(exception);
        }
    }

    /**
     * Метод читает данные из XML и записывает их в поля
     */
    public void loadDataFromXML(InputStream inputStream) throws InputDataException
    {
        try
        {
            loadDataFromXML(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(inputStream));
        }
        catch (Exception exception)
        {
            throw new InputDataException(exception);
        }
    }

    /**
     * Метод читает данные из XML и записывает их в поля
     */
    public void loadDataFromXML(File file) throws InputDataException
    {
        try
        {
            loadDataFromXML(DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(file));
        }
        catch (Exception exception)
        {
            throw new InputDataException(exception);
        }
    }

    /**
     * Метод клонирует объект
     * @return Экземпляр класса InputData
     */
    @Override
    public InputData clone()
    {
        InputData result = new InputData();
        result.materialStockList = new ArrayList();
        for (MaterialStock thisMaterialCount : this.materialStockList)
        {
            result.materialStockList.add(new MaterialStock(new Material(thisMaterialCount.getMaterial()), thisMaterialCount.getCount()));
        }
        result.formatOrderList = new ArrayList();
        for (FormatOrder thisFormatCount : this.formatOrderList)
        {
            result.formatOrderList.add(new FormatOrder(new Format(thisFormatCount.getFormat()), thisFormatCount.getCount()));
        }
        return result;
    }

    /**
     * Метод вычищает списки
     */
    public void clear()
    {
        materialStockList.clear();
        formatOrderList.clear();
    }

    /**
     *
     * @return Общая длина всех типов материалов
     */
    public int getMaterialArea()
    {
        int result = 0;
        for (MaterialStock materialCount : materialStockList)
        {
            result += materialCount.getCount() * materialCount.getMaterial().getLength();
        }
        return result;
    }

    /**
     *
     * @return Общая длина всех требуемых форматов
     */
    public int getFormatArea()
    {
        int result = 0;
        for (FormatOrder formatCount : formatOrderList)
        {
            result += formatCount.getCount() * formatCount.getFormat().getLength();
        }
        return result;
    }

    /**
     *
     * @return Количество всех материалов
     */
    public int getMaterialCountSum()
    {
        int result = 0;
        for (MaterialStock materialCount : materialStockList)
        {
            result += materialCount.getCount();
        }
        return result;
    }

    /**
     *
     * @return Количество всех форматов
     */
    public int getFormatCountSum()
    {
        int result = 0;
        for (FormatOrder formatCount : formatOrderList)
        {
            result += formatCount.getCount();
        }
        return result;
    }

    /**
     *
     * @return Количество различных длин материалов
     */
    public int getDiffMaterialLengthCount()
    {
        List<Integer> differentLengths = new ArrayList();
        for (MaterialStock materialCount : materialStockList)
        {
            boolean notMatch = true;
            for (Integer integer : differentLengths)
            {
                if (integer.intValue() == materialCount.getMaterial().getLength())
                {
                    notMatch = false;
                }
            }
            if (notMatch)
            {
                differentLengths.add(new Integer(materialCount.getMaterial().getLength()));
            }
        }
        return differentLengths.size();
    }

    /**
     *
     * @return Количество различных длин форматов
     */
    public int getDiffFormatLengthCount()
    {
        List<Integer> differentLengths = new ArrayList();
        for (FormatOrder formatCount : formatOrderList)
        {
            boolean notMatch = true;
            for (Integer integer : differentLengths)
            {
                if (integer.intValue() == formatCount.getFormat().getLength())
                {
                    notMatch = false;
                }
            }
            if (notMatch)
            {
                differentLengths.add(new Integer(formatCount.getFormat().getLength()));
            }
        }
        return differentLengths.size();
    }
}
